package com.zt.bigdata.practise.javastrategy.chapter3;

import com.zt.bigdata.practise.javastrategy.chapter1.dto.Person;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 *
 */
public class Chapter3 {
    public static void main(String[] args) {
        //static <T> Stream<T> of(T... values)
        //3.1 流的创建
        String names = Stream.of("Gomez", "Morticia", "Wednesday", "Pugsley")
                .collect(Collectors.joining(","));

        System.out.println(names);
        String[] munsters = {"Herman", "Lily", "Eddie", "Marilyn", "Grandpa"};
        names = Arrays.stream(munsters)
                .collect(Collectors.joining(","));

        //public interface UnaryOperator<T> extends Function<T, T> 一元操作
        List<BigDecimal> nums = Stream
                .iterate(
                        BigDecimal.ONE,
                        bigDecimal -> bigDecimal.multiply(new BigDecimal(2))
                )
                .limit(10).collect(Collectors.toList());
        System.out.println(nums);

        Stream.iterate(LocalDate.now(), ld -> ld.plusDays(1L))
                .limit(10)
                .forEach(System.out::println);
        long count = Stream.generate(Math::random)
                .limit(10)
                .count();

        IntStream.range(10, 15).boxed().count();

        LongStream.generate(() -> System.currentTimeMillis())
                .limit(10)
                .forEach(value -> System.out.println(value));

        //3.2 装箱流
        List<String> strings = Stream.of("this", "is", "a", "list", "of", "strings")
                .collect(Collectors.toList());
        //IntStream.of(3, 1, 4, 1, 5, 9) .collect(Collectors.toList()); //编译失败 int 需要boxed
        IntStream.of(3, 1, 4, 1, 5, 9).boxed().collect(Collectors.toList());

        List<Integer> ints = IntStream.of(3, 1, 4, 1, 5, 9)
                .mapToObj(Integer::valueOf)
                .collect(Collectors.toList());

        ints = IntStream.of(3, 1, 4, 1, 5, 9)
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

        System.out.println(ints);

        //3.3 利用reduce方法实现归约操作
        String[] split = "this is an array of strings".split(" ");

        long splitCount = Arrays.stream(split)
                .map(String::length)
                .count();
        System.out.println("There are " + splitCount + " strings");

        Arrays.stream(split)
                .mapToInt(String::length).sum();
        Arrays.stream(split)
                .mapToInt(String::length).average();
        Arrays.stream(split)
                .mapToInt(String::length).max();

        //没有初始值
        IntStream.rangeClosed(1, 10)
                .reduce(((left, right) -> left + right)).orElse(0);
        //默认初始值
        IntStream.rangeClosed(1, 10)
                .reduce(0, ((left, right) -> left + right));

        IntStream.rangeClosed(1, 10)
                .reduce(0, Integer::sum);
        Stream.of(3, 1, 4, 1, 5, 9)
                .reduce(1, Chapter3::aaa);

        //字符串拼接
        System.out.println(Stream.of("this", "is", "a", "list")
                .collect(
                        () -> new StringBuilder(),  //Supplier 是一个function 不能使用 new StringBuilder()
                        (sb, str) -> sb.append(str + " "), //
                        (sb1, sb2) -> sb1.append(sb2)
                ).toString()
        );

        Stream.of("this", "is", "a", "list")
                .collect(
                        StringBuilder::new,
                        StringBuilder::append,
                        StringBuilder::append
                )
                .toString();

        Stream.of("this", "is", "a", "list")
                .collect(Collectors.joining(" "));

      /*
          <U> U reduce(U identity,
                 BiFunction<U, ? super T, U> accumulator,
                 BinaryOperator<U> combiner);
      */
        int sum = Stream.of(3, 1, 4, 1, 5, 9)
                .reduce(0,
                        (integer, integer2) -> integer + integer2,
                        (integer, integer2) -> integer + integer2
                );
        System.out.println("-------》" + sum);
        sum = Stream.of(3, 1, 4, 1, 5, 9)
                .reduce(0, Integer::sum, Integer::sum);
        System.out.println(sum);

        Map<String, Person> personMap = Stream.of(munsters).map(Person::new)
                .reduce(
                        new HashMap<>(),  //初始集合 也是最终返回的集合
                        (map, person) -> {
                            map.put(person.getName(), person);   //中间处理过程 将 person 添加到 map
                            return map;
                        },
                        (map1, map2) -> {
                            map1.putAll(map2);     //最后处理  将多个map进行合并
                            return map1;
                        }
                );

        System.out.println(personMap);

        System.out.println(aaa(1, 2, (a, b) -> a * b));
        System.out.println(aaa(1, 2, Chapter3::aaa));

        //3.4 利用reduce方法校验排序
        Arrays.asList(
                "this", "is", "a", "list", "of", "strings")
                .stream()
                .sorted(Comparator.comparingInt(String::length))
                .collect(Collectors.toList())
                .stream()
                .reduce(
                        (pre, curr) -> {
                            if (pre.length() <= curr.length()) {
                                return curr;
                            } else {
                                throw new RuntimeException("排序错误");
                            }
                        }
                );

        //3.5 利用peek方法对流进行调试
        IntStream.rangeClosed(1, 100)
                .peek(n -> System.out.printf("original: %d%n", n))//不会对当前流产生影响
                .map(n -> n * 2)
                .peek(n -> System.out.printf("doubled : %d%n", n))
                .filter(n -> n % 3 == 0)
                .peek(n -> System.out.printf("filtered: %d%n", n))
                .sum();

        isPalindrome("Ab,a");

        //3.8 汇总统计
        DoubleSummaryStatistics stats = DoubleStream.generate(Math::random)
                .limit(1_000_000)
                .summaryStatistics();
        System.out.println(stats);

        Integer a = 1000, b = 1000;
        System.out.println(a == b);
        a = 100;
        b = 100;
        System.out.println(a == b);

        //3.9 查找流的第一个元素
        Optional<Integer> firstEven = Stream.of(3, 1, 4, 1, 5, 9, 2, 6, 5)
                .filter(n -> n % 2 == 0)
                .findFirst();
        Optional<Integer> any = Stream.of(3, 1, 4, 1, 5, 9, 2, 6, 5)
                .unordered()
                .map(Chapter3::delay).findAny();

        //3.10 使用anyMatch、allMatch与noneMatch方法
        isPrime(10);

        //3.11 使用flatMap与map方法
        Stream.of("dddd,aaa", "eee,aaa")
                .flatMap(s -> Stream.of(s.split(","))).forEach(System.out::println);
        Stream.of("dddd,aaa", "eee,aaa")
                .flatMap(s -> Stream.of(s)).forEach(System.out::println);

        customerBuilder().stream()
                .map(Customer::getName) //Function<? super T, ? extends R> mapper    T -> R
                .forEach(System.out::println);
        customerBuilder().stream()
                .map(customer -> customer.getOrders().stream())//Function<? super T, ? extends R> mapper    T -> Stream<R>
                .forEach(s -> System.out.println(s)); //s 是Stream<Order>类型

        //flatMap  <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) T->Stream<R>
        customerBuilder().stream()
                .flatMap(customer -> customer.getOrders().stream())//T->Stream<R>
                .forEach(s -> System.out.println(s)); //s 是Order类型  内嵌流被拉平
    }

    private static int aaa(int a, int b) {
        return a + b;
    }

    private static <T> T aaa(T t1, T t2, BinaryOperator<T> binaryOperator) {
        return binaryOperator.apply(t1, t2);
    }

    public static boolean isPalindrome(String s) {
        String forward = s.toLowerCase().codePoints()
                .filter(Character::isLetterOrDigit)
                .collect(StringBuilder::new,
                        StringBuilder::appendCodePoint,
                        StringBuilder::append)
                .toString();
        String backward = new StringBuilder(forward).reverse().toString();
        return forward.equals(backward);
    }

    private static Integer delay(Integer n) {
        try {
            Thread.sleep((long) (Math.random() * 100));
        } catch (InterruptedException ignored) {

        }
        return n;
    }

    /**
     * 质数校验
     *
     * @param num
     * @return
     */
    public static boolean isPrime(int num) {
        int limit = (int) (Math.sqrt(num) + 1);
        return num == 2 || num > 1 && IntStream.range(2, limit)
                .noneMatch(divisor -> num % divisor == 0);//校验是否能找到整除的约数
    }

    public static List<Customer> customerBuilder() {
        Customer sheridan = new Customer("Sheridan");
        Customer ivanova = new Customer("Ivanova");
        Customer garibaldi = new Customer("Garibaldi");
        sheridan.addOrder(new Order(1)).addOrder(new Order(2))
                .addOrder(new Order(3));
        ivanova.addOrder(new Order(4))
                .addOrder(new Order(5));
        List<Customer> customers = Arrays.asList(sheridan, ivanova, garibaldi);
        return customers;
    }
}
